using System;
using System.Collections.Generic;
using System.Text;
using StructureMap;
using NUnit.Framework;
using NMock2;

using Impact.Controllers;
using Impact.Views;
using Impact.Infrastructure.Configuration;
using Impact.Infrastructure.Logging;
using Impact.UnitTests.Mocks;
using Impact.Model.Service;
using NMock2.Actions;
using Impact.Model.Objects;
using System.Collections.Specialized;

namespace Impact.UnitTests
{

    public class UTContentPresenter : TestFixtureBase
    {


        #region Requests for Page

        [Test]
        public void RequestForPageTwo()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(new Uri("http://localhost/two.ashx", UriKind.Absolute)));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayPage.ascx"), Is.NotNull, Is.Null);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void RequestForDefaultPage()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(new Uri("http://localhost/default.aspx", UriKind.Absolute)));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayPage.ascx"), Is.NotNull, Is.Null);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();
        }


        [Test]
        public void RequestForNonExistantPage()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(new Uri("http://localhost/nonExistant.ashx", UriKind.Absolute)));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(view).Method("ShowErrorMessage").With(Is.NotNull);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void RequestForDisabledPage()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(new Uri("http://localhost/three.ashx", UriKind.Absolute)));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(view).Method("ShowErrorMessage").With(Is.NotNull);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();
        }

        [Test]
        public void RequestForPageThatIsTemplate()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(new Uri("http://localhost/four.ashx", UriKind.Absolute)));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(view).Method("ShowErrorMessage").With(Is.NotNull);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();
        }


        [Test]
        public void RequestForPageThatIsHyperlink()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(new Uri("http://localhost/five.ashx", UriKind.Absolute)));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(handler).Method("Redirect").With(Is.NotNull);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();
        }

        #endregion

        #region Articles Requests

        [Test]
        public void RequestForCategory()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            ICategoryService categoryService = ObjectFactory.GetInstance<ICategoryService>();
            ArticleCategory category = categoryService.FetchByID(1);
            Uri categoryUrl = new Uri(ResolveClientUrl(ContentPresenter.FormatUrl(category)), UriKind.Absolute);

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(categoryUrl));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayCategory.ascx"), Is.EqualTo(category), Is.Null);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        [Test]
        public void RequestForNonExistantCategory()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            ICategoryService categoryService = ObjectFactory.GetInstance<ICategoryService>();

            Uri categoryUrl = new Uri(ResolveClientUrl("~/test/doesntexist.ashx"), UriKind.Absolute);
            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(categoryUrl));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(view).Method("ShowErrorMessage").With(Is.NotNull);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }


        [Test]
        public void RequestForTag()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            ITagService tagService = ObjectFactory.GetInstance<ITagService>();
            Tag tag = tagService.FetchByID(1);
            Uri tagUrl = new Uri(ResolveClientUrl(ContentPresenter.FormatUrl(tag)), UriKind.Absolute);

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(tagUrl));
            Expect.AtLeastOnce.On(handler).Method("DecodeUrl").Will(Process.AndReturnSameValue());

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayTag.ascx"), Is.EqualTo(tag), Is.Null);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        [Test]
        public void RequestForInvalidTag()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            ITagService tagService = ObjectFactory.GetInstance<ITagService>();
            Uri tagUrl = new Uri(ResolveClientUrl("~/test/tags/doesntExist.ashx"), UriKind.Absolute);

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(tagUrl));
            Expect.AtLeastOnce.On(handler).Method("DecodeUrl").Will(Process.AndReturnSameValue());

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("ShowErrorMessage").With(Is.NotNull);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        [Test]
        public void RequestForArticle()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            IArticleService articleService = ObjectFactory.GetInstance<IArticleService>();
            Article article = articleService.FetchByID(1);
            Uri articleUrl = new Uri(ResolveClientUrl(ContentPresenter.FormatUrl(article)), UriKind.Absolute);

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(articleUrl));
            Expect.AtLeastOnce.On(handler).GetProperty("UserHostAddress").Will(Return.Value("127.0.0.1"));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayArticle.ascx"), Is.EqualTo(article), Is.Null);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        [Test]
        public void ArticleIncrementUserViews()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            IArticleService articleService = ObjectFactory.GetInstance<IArticleService>();
            Article article = articleService.FetchByID(1);
            Uri articleUrl = new Uri(ResolveClientUrl(ContentPresenter.FormatUrl(article)), UriKind.Absolute);

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(articleUrl));
            Expect.AtLeastOnce.On(handler).GetProperty("UserHostAddress").Will(Return.Value("127.0.0.1"));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayArticle.ascx"), Is.EqualTo(article), Is.Null);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            Assert.AreEqual(1, article.UserViews);
            mocks.VerifyAllExpectationsHaveBeenMet();

            // step two

            handler = mocks.NewMock<IContentHandler>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(articleUrl));
            // different URL
            Expect.AtLeastOnce.On(handler).GetProperty("UserHostAddress").Will(Return.Value("127.0.0.2"));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayArticle.ascx"), Is.EqualTo(article), Is.Null);

            presenter = new ContentPresenter(handler, view);

            Assert.AreEqual(2, article.UserViews);
            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        [Test]
        public void RequestForInvalidArticle()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Uri articleUrl = new Uri(ResolveClientUrl("~/test/99/one/doesntExist.ashx"), UriKind.Absolute);
            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(articleUrl));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(view).Method("ShowErrorMessage").With(Is.NotNull);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        [Test]
        public void RequestForCategories()
        {

            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Uri articleUrl = new Uri(ResolveClientUrl("~/test/categories.ashx"), UriKind.Absolute);
            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(articleUrl));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayCategories.ascx"), Is.Null, Is.Null);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        #endregion

        #region Search

        [Test]
        public void RequestForSearch()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Uri articleUrl = new Uri(ResolveClientUrl("~/!search.ashx"), UriKind.Absolute);
            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(articleUrl));

            NameValueCollection queryString = new NameValueCollection();
            queryString.Add("terms", "item");
            Expect.AtLeastOnce.On(handler).GetProperty("QueryString").Will(Return.Value(queryString));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplaySearchResults.ascx"), Is.NotNull, Is.Null);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        [Test]
        public void RequestForSearchNoTerms()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Uri articleUrl = new Uri(ResolveClientUrl("~/!search.ashx"), UriKind.Absolute);
            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(articleUrl));

            NameValueCollection queryString = new NameValueCollection();
            Expect.AtLeastOnce.On(handler).GetProperty("QueryString").Will(Return.Value(queryString));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));
            Expect.Once.On(view).Method("ShowErrorMessage").With(Is.NotNull);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        #endregion

        #region Preview

        [Test]
        public void RequestForPreviewOfDisabledPage()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(new Uri("http://localhost/!preview.ashx", UriKind.Absolute)));

            NameValueCollection queryString = new NameValueCollection();
            queryString.Add("pageId", "3");
            Expect.AtLeastOnce.On(handler).GetProperty("QueryString").Will(Return.Value(queryString));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayPage.ascx"), Is.NotNull, Is.Null);


            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        [Test]
        public void RequestForPreviewOfArticle()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(new Uri("http://localhost/!preview.ashx", UriKind.Absolute)));

            NameValueCollection queryString = new NameValueCollection();
            queryString.Add("articleId", "3");
            Expect.AtLeastOnce.On(handler).GetProperty("QueryString").Will(Return.Value(queryString));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("Render").With(
                Is.StringContaining("~/Controls/DisplayArticle.ascx"), Is.NotNull, Is.Null);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();

        }

        [Test]
        public void RequestForPreviewWithNoParameters()
        {
            Mockery mocks = new Mockery();
            IContentHandler handler = mocks.NewMock<IContentHandler>();
            IContentView view = mocks.NewMock<IContentView>();

            Expect.AtLeastOnce.On(handler).GetProperty("RequestUrl").Will(Return.Value(new Uri("http://localhost/!preview.ashx", UriKind.Absolute)));

            NameValueCollection queryString = new NameValueCollection();
            Expect.AtLeastOnce.On(handler).GetProperty("QueryString").Will(Return.Value(queryString));

            Expect.Once.On(view).EventAdd("Load", Is.Anything).Will(FireEvent.With(view));

            Expect.Once.On(view).Method("ShowErrorMessage").With(Is.NotNull);

            ContentPresenter presenter = new ContentPresenter(handler, view);

            mocks.VerifyAllExpectationsHaveBeenMet();
        }

        #endregion

        #region Formatters

        [Test]
        public void FormatPageArticleTag()
        {
            ArticleTag tag = new ArticleTag();
            tag.TagId = 99;
            tag.ArticleId = 1;
            tag.Text = "Nine, Nine";

            string tagUrl = ContentPresenter.FormatUrl(tag);
            Assert.IsNotEmpty(tagUrl);

            Uri result = null;
            Assert.IsTrue(Uri.TryCreate(tagUrl, UriKind.Relative, out result));
            Assert.IsNotNull(result);
        }

        [Test]
        public void FormatPageTag()
        {
            Tag tag = new Tag();
            tag.TagId = 99;
            tag.Text = "Nine, Nine";

            string tagUrl = ContentPresenter.FormatUrl(tag);
            Assert.IsNotEmpty(tagUrl);

            Uri result = null;
            Assert.IsTrue(Uri.TryCreate(tagUrl, UriKind.Relative, out result));
            Assert.IsNotNull(result);
        }

        [Test]
        public void FormatArticleCategory()
        {
            ArticleCategory category = new ArticleCategory();
            category.CategoryId = 11;
            category.Name = "eleven";
            category.NameKey = "eleven";

            string catUrl = ContentPresenter.FormatUrl(category);
            Assert.IsNotEmpty(catUrl);

            Uri result = null;
            Assert.IsTrue(Uri.TryCreate(catUrl, UriKind.Relative, out result));
            Assert.IsNotNull(result);
        }

        [Test]
        public void FormatPageUrl()
        {
            ImpactPage page = new ImpactPage();
            page.PageId = 13;
            page.PageKey = "thirteen";
            page.Caption = "Lucky Thirteen";
            page.Body = "all about it";
            page.Enabled = true;
            page.Sequence = 13;
            page.Title = "thirteen";
            page.Type = PageType.Page.TypeId;

            string pageUrl = ContentPresenter.FormatUrl(page);
            Assert.IsNotEmpty(pageUrl);

            Uri result = null;
            Assert.IsTrue(Uri.TryCreate(pageUrl, UriKind.Relative, out result));
            Assert.IsNotNull(result);

        }

        [Test]
        public void FormatCommentUrl()
        {
            ArticleComment comment = new ArticleComment();
            comment.CommentId = 123;
            comment.ArticleId = 1;
            comment.Body = "test comment one";

            string commentUrl = ContentPresenter.FormatUrl(comment);
            Assert.IsNotEmpty(commentUrl);

            Uri result = null;
            Assert.IsTrue(Uri.TryCreate(commentUrl, UriKind.Relative, out result));
            Assert.IsNotNull(result);
        }

        [Test]
        public void FormatArticleUrl()
        {
            Article article = new Article();
            article.ArticleId = 1234;
            article.Body = "one two three four";
            article.CategoryId = 3;
            article.Enabled = true;
            article.Title = "onetwothreefour";

            string articleUrl = ContentPresenter.FormatUrl(article);
            Assert.IsNotEmpty(articleUrl);

            Uri result = null;
            Assert.IsTrue(Uri.TryCreate(articleUrl, UriKind.Relative, out result));
            Assert.IsNotNull(result);

        }


        #endregion


        #region Helpers


        private static string ResolveClientUrl(string url)
        {
            return url.Replace("~/", "http://localhost/");
        }


        private class Process : IAction
        {

            public static IAction AndReturnSameValue()
            {
                return new Process();
            }

            public void Invoke(NMock2.Monitoring.Invocation invocation)
            {
                invocation.Result = invocation.Parameters[0];
                

            }

            public void DescribeTo(System.IO.TextWriter writer)
            {
            }

        }

        private class FireEvent : IAction
        {
            public static IAction With(object withSender)
            {
                return new FireEvent(withSender);
            }

            private object sender;

            public FireEvent(object sender)
            {
                this.sender = sender;
            }

            public void Invoke(NMock2.Monitoring.Invocation invocation)
            {
                EventHandler handler = (EventHandler)invocation.Parameters[0];
                handler.Invoke(sender, new EventArgs());
            }

            public void DescribeTo(System.IO.TextWriter writer)
            {
            }

        }

        #endregion


    }
}
